Hero = function(battleTag, id, callback) {

	getHero(battleTag, id, callback);

	function getHero() {
		$.ajax({
			url: 'hero.php',
			data: { 'battle_tag' : battleTag, 'id' : id },
			success: function(hero) {
				obj.data = hero;

				if(callback) {
					callback('hero');
				}
				console.log(hero);
				for(var part in hero.items) {
					var itemData = hero.items[part].tooltipParams;
					var item = localStorage.getItem(itemData);
			
					if(item)
					{
						item = $.parseJSON(item);
						item = new Item(item);	
						obj.data.items[part] = item;
						
						var done = true;
						for(var part in hero.items) {
							if(!hero.items[part].done) {
								done = false;
							}
						}
								
						if(done)
							callback();										
					}
					else
					{
						$.ajax({
							url: 'item.php',
							data: { 'item_data' : itemData },
							success: function(item) {																								
								var itemStr = item;								
								item = $.parseJSON(item);
								localStorage.setItem(item.tooltipParams, itemStr);
								item = new Item(item);	
								obj.data.items[part] = item;
								
								var done = true;
								for(var part in hero.items) {
									if(!hero.items[part].done) {
										done = false;
									}
								}
								
								if(done)
									callback();										
							}
						});			
					}
				}			
			}
		});
	}
	
	function getTotalAttribute(name) {
		var x = 0;

		switch(name) {
			case 'str': 
				if(this.data.class == 'barbarian')
					x = 10 + 3 * (this.data.level - 1 + this.data.paragonLevel);
				else
					x = 8 + this.data.level - 1 + this.data.paragonLevel;
				break;
			case 'dex':
				if(this.data.class == 'demon-hunter' || this.data.class == 'monk')
					x = 10 + 3 * (this.data.level - 1 + this.data.paragonLevel);
				else
					x = 8 + this.data.level - 1 + this.data.paragonLevel;
				break;
			case 'int':
				if(this.data.class == 'witch-doctor' || this.data.class == 'wizard')
					x = 10 + 3 * (this.data.level - 1 + this.data.paragonLevel);
				else
					x = 8 + this.data.level - 1 + this.data.paragonLevel;
				break;
			case 'vit':
				x = 9 + 2 * (this.data.level - 1 + this.data.paragonLevel);
				break;
			case 'aspd':
				x = 0;
				break;
			case 'crit':
				x = 0.05;
				break;
			case 'chd':
				x = 0.5;
				break;
			case 'min':
			case 'max':
				if(this.isDualWield()){					
					return this.getTotalAttribute(name + '_main') + this.getTotalAttribute(name + '_off');
				}
				else {
					for(var part in this.data.items) {						
						if(this.data.items[part].getDamage)
							x += this.data.items[part].getDamage(name);
					}
					return x;
				}
			//if dual wield, separate main and off hand min/max damage
			case 'min_main':
			case 'max_main':
				name = name.replace('_main', '');
			
				for(var part in this.data.items) {		
					if(part == 'offHand')
						continue;
				
					if(this.data.items[part].getDamage)
						x += this.data.items[part].getDamage(name);
				}
				return x;
			case 'min_off':
			case 'max_off':
				name = name.replace('_off', '');
			
				for(var part in this.data.items) {		
					if(part == 'mainHand')
						continue;
				
					if(this.data.items[part].getDamage)
						x += this.data.items[part].getDamage(name);
				}		
				return x;
			case 'baspd':	
				if(this.isDualWield()){
					if(this.data.items.mainHand.getAttackSpeed && this.data.items.offHand.getAttackSpeed)
						return ((this.data.items.mainHand.getAttackSpeed() + this.data.items.offHand.getAttackSpeed()) / 2) * 1.15;
				}
				else {
					if(this.data.items.mainHand.getAttackSpeed)
						return this.data.items.mainHand.getAttackSpeed();
				}
				break;			
			case 'baspd_main':
				if(this.data.items.mainHand.getAttackSpeed)
					return this.data.items.mainHand.getAttackSpeed();
				break;
			case 'baspd_off':
				if(this.data.items.offHand.getAttackSpeed)
					return this.data.items.offHand.getAttackSpeed();
				break;
			default:
				console.error('Unknown Parameter: ' + name);
				break;				
		}
		
		for(var part in this.data.items) {	
			//dont include mainhand aspd and offhand aspd(if dual wielding)
			var dualWield = this.isDualWield();	
				
			if(name == 'aspd' && (part == 'mainHand' || (part == 'offHand' && dualWield)))
				continue;
			
			if(this.data.items[part].getAttribute)
				x += this.data.items[part].getAttribute(name);
		}
				
		return x;
	}
	
	function calculateDPS() {		
		var s = 1
				
		switch(this.data.class)
		{
			case 'barbarian':
				s += this.getTotalAttribute('str') / 100;
				break;
			case 'demon-hunter':
			case 'monk':
				s += this.getTotalAttribute('dex') / 100;
				break;
			case 'witch-doctor':
			case 'wizard':
				s += this.getTotalAttribute('int') / 100;
				break;
			default:
				console.error('Unknown Class: ' + this.data.class);
				break;
		}
	
		var c = 1 + (this.getTotalAttribute('crit') * this.getTotalAttribute('chd'));
		var r = this.getTotalAttribute('baspd') * (1 + this.getTotalAttribute('aspd'));
		var a = (this.getTotalAttribute('max') + this.getTotalAttribute('min') * 2) / 2;
		var m = 1;
		
		if(this.isDualWield && this.isDualWield())
		{			
			var r1 = this.getTotalAttribute('baspd_main');
			var r2 = this.getTotalAttribute('baspd_off');
			r = (r1 * r2) / (r1 + r2) * (1.15 + this.getTotalAttribute('aspd'));
		}		
			
		return Math.ceil(s*c*r*a*m * 100) / 100;
	}
	
	function isDualWield() {		
		var dualWield = false;
		if(this.data.items.offHand.isWeapon)
			dualWield = this.data.items.offHand.isWeapon();
			
		return dualWield;
	}
	
	var obj = {
		data : {},
		getTotalAttribute : getTotalAttribute,
		calculateDPS : calculateDPS,
		isDualWield : isDualWield
	};

	return obj;
}